import logging
log = logging.getLogger('log')

import hmac
import hashlib
import json
import unittest
from collections import OrderedDict
from apps.generate_secret.models import AppSecret
import re
from datetime import datetime, timedelta
from django.conf import settings


def generate_signature(body_dict, app_secret):
    """
    生成HMAC-SHA256签名

    :param body_dict: 请求体参数字典（仅一级字段）
    :param app_secret: 应用密钥
    :return: 十六进制格式的签名字符串
    """
    #  拼接键值对字符串
    sign_str = f'senderNonce={body_dict["senderNonce"]}&messageTime={body_dict["messageTime"]}&app_secret={app_secret}'

    #  计算HMAC-SHA256摘要
    signature = hmac.new(
        key=app_secret.encode('utf-8'),
        msg=sign_str.encode('utf-8'),
        digestmod=hashlib.sha256
    ).hexdigest()
    log.info(f"param: {sign_str}")
    log.info(f"Token: {signature}")

    return signature


def get_signed_headers(body_dict, app_secret):
    """
    获取包含签名头的完整请求头

    :param body_dict: 请求体参数字典
    :param app_secret: 应用密钥
    :return: 包含签名头的字典
    """
    signature = generate_signature(body_dict, app_secret)
    return {
        "signAlg": "HMAC-SHA256",
        "sign": signature
    }


def validate_signature_token(app_id, senderNonce, messageTime, token):
    """
    校验签名token是否有效（供外部app调用）
    :param app_id: 应用ID
    :param senderNonce: 发送方随机数
    :param messageTime: 消息时间，必须为yyyyMMddHHmmssSSS格式
    :param token: 待校验的签名token
    :return: tuple, (是否有效, 错误信息)，如(True, None)或(False, "错误描述")
    """
    # 校验messageTime格式
    if not isinstance(messageTime, str) or not re.fullmatch(r"\d{17}", messageTime):
        return False, "messageTime格式错误，必须为yyyyMMddHHmmssSSS格式（17位数字）"
    
    # 校验时间范围
    try:
        # 解析messageTime
        message_datetime = datetime.strptime(messageTime, "%Y%m%d%H%M%S%f")
        current_datetime = datetime.now()
        
        # 从配置文件获取允许的时间范围（小时），默认为24小时
        time_tolerance_hours = getattr(settings, 'SIGNATURE_TIME_TOLERANCE_HOURS', 24)
        time_tolerance = timedelta(hours=time_tolerance_hours)
        
        # 检查时间差是否在允许范围内
        time_diff = abs(current_datetime - message_datetime)
        if time_diff > time_tolerance:
            return False, f"时间超出允许范围，当前时间差为{time_diff.total_seconds()/3600:.1f}小时，允许范围为{time_tolerance_hours}小时"
    except ValueError:
        # 时间格式解析失败
        return False, "messageTime时间格式解析失败"
    
    # 查询app_secret
    app_secret_obj = AppSecret.objects.filter(app_id=app_id, is_delete=False, status=True).first()
    if not app_secret_obj:
        return False, "应用不存在或已被禁用"
    app_secret = app_secret_obj.app_secret
    # 构建签名参数
    signature_params = {
        "app_id": app_id,
        "senderNonce": senderNonce,
        "messageTime": messageTime
    }
    # 生成签名
    expected_token = generate_signature(signature_params, app_secret)
    # 比较token
    if token == expected_token:
        return True, None
    else:
        return False, "签名token不匹配"

def get_client_ip(request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
def validate_signature(headers, body):
    """
    公共签名校验函数
    从头信息获取app_id和token，从参数获取senderNonce、recipNonce、messageTime
    调用validate_signature_token进行检测
    """
    # 从头信息获取app_id和token
    app_id = headers.get('Appid')
    token = headers.get('Sign')
    alg_type= headers.get('Signalg')
    
    # 从请求参数获取其他参数
    sender_nonce = body.get('senderNonce')
    # recip_nonce = body.get('recipNonce')
    message_time = body.get('messageTime')
    
    log.info(f"签名校验参数 - {alg_type}, app_id: {app_id}, token长度: {len(token) if token else 0}, senderNonce: {sender_nonce}, messageTime: {message_time}")
    
    # 参数校验
    if not app_id:
        log.warning("签名校验失败: 缺少app_id头信息")
        return False, "缺少app_id头信息"
    if not token:
        log.warning("签名校验失败: 缺少token头信息")
        return False, "缺少token头信息"
    if not sender_nonce:
        log.warning("签名校验失败: 缺少senderNonce参数")
        return False, "缺少senderNonce参数"
    # if not recip_nonce:
        # log.warning("签名校验失败: 缺少recipNonce参数")
        # return False, "缺少recipNonce参数"
    if not message_time:
        log.warning("签名校验失败: 缺少messageTime参数")
        return False, "缺少messageTime参数"
    
    # 调用validate_signature_token进行校验
    result = validate_signature_token(app_id, sender_nonce, message_time, token)
    if result[0]:
        log.info(f"签名校验成功 - app_id: {app_id}")
    else:
        log.warning(f"签名校验失败 - app_id: {app_id}, 错误: {result[1]}")
    return result